import com.mochimedia.ui.TweenManager;
import com.robertpenner.easing.*;

/**
 * Class: TweenManager
 * Describes a single tween of one parameter of a single MovieClip
 * Must be used in a TweenManager instance to function
 * @version 1.0
 */
class com.mochimedia.ui.Tween {

    public static var EASE_IN:Number = 0;
    public static var EASE_OUT:Number = 1;
    public static var EASE_INOUT:Number = 2;
    
    public static var STYLE_LINEAR:Number = 0;
    public static var STYLE_CUBIC:Number = 1;
    public static var STYLE_QUAD:Number = 2;
    public static var STYLE_QUART:Number = 3;
    public static var STYLE_QUINT:Number = 4;
    public static var STYLE_SINE:Number = 5;
    public static var STYLE_EXPO:Number = 6;
    public static var STYLE_CIRC:Number = 7;
    public static var STYLE_ELASTIC:Number = 8;
    public static var STYLE_BACK:Number = 9;
    public static var STYLE_BOUNCE:Number = 10;
    
    private var _id:Number;
    private var _parentClass:TweenManager;
    
    private var tweenClassRef:Object;
    private var easeMethod:String = "easeIn";
    
    private var _clip:Object;
    private var _attribute:String;
    private var _startVal:Number;
    private var _endVal:Number;
    private var _duration:Number;
    
    private var _easeType:Number = 0;
    private var _easeStyle:Number = 0;
    
    private var _pixelSnap:Boolean = false;
    
    private var _startTime:Number;
    private var _delay:Number;
    private var _time:Number;
    
    private var _done:Boolean = false;
    
    private var _startHandler:Function;
    private var _doneHandler:Function;
    private var _tweenHandler:Function;
    
    private var _started:Boolean = false;
    
    public function get id ():Number { return _id; }
    public function get clip ():Object { return _clip; }
    public function get attribute ():String { return _attribute; }

    //
    //
    public function Tween (parentClass:TweenManager, clip:Object, attribute:String, startVal:Object, endVal:Object, duration:Number, delay:Number, pixelSnap:Boolean, easeType:Number, easeStyle:Number, startHandler:Function, doneHandler:Function, tweenHandler:Function) {
        
        init(parentClass, clip, attribute, startVal, endVal, duration, delay, pixelSnap, easeType, easeStyle, startHandler, doneHandler, tweenHandler);
        
    }
    
    //
    //
    private function init (parentClass:TweenManager, clip:Object, attribute:String, startVal:Object, endVal:Object, duration:Number, delay:Number, pixelSnap:Boolean, easeType:Number, easeStyle:Number, startHandler:Function, doneHandler:Function, tweenHandler:Function):Void {
        
        _parentClass = parentClass;
        _id = _parentClass.newTweenID;
        
        _clip = clip;
        _attribute = attribute;
        

        if (typeof(startVal) == "string") {
            _startVal = parseFloat(clip[attribute]) + parseFloat(String(startVal));
        } else {
            _startVal = (startVal != null) ? parseFloat(String(startVal)) : (attribute != "scale") ? clip[attribute] : clip._xscale;
        }
        
        if (typeof(endVal) == "string") {
            _endVal = parseFloat(clip[attribute]) + parseFloat(String(endVal));
        } else {
            _endVal = (endVal != null) ? parseFloat(String(endVal)) - _startVal : (attribute != "scale") ? clip[attribute] - _startVal : clip._xscale;
        }

        _duration = (!isNaN(duration) && duration != null) ? duration : 1;
        _delay = (!isNaN(delay) && delay != null) ? delay : 0;
        
        if (_duration < 100) _duration *= 1000;
        if (_delay < 100) _delay *= 1000;
        
        if (pixelSnap) _pixelSnap = true;
        
        _easeType = (!isNaN(easeType) && easeType != null) ? easeType : EASE_IN;
        _easeStyle = (!isNaN(easeStyle) && easeStyle != null) ? easeStyle : STYLE_LINEAR;
        
        _startHandler = startHandler;
        _doneHandler = doneHandler;
        _tweenHandler = tweenHandler;
        
        getTweenClass();
        getEaseMethod();
        
    }
    
    //
    //
    private function getTweenClass ():Void {
            
        switch (_easeStyle) {
            
            case Tween.STYLE_LINEAR:
            
                tweenClassRef = Linear;
                break;
                
            case Tween.STYLE_LINEAR:
            
                tweenClassRef = Linear;
                break;
                
            case Tween.STYLE_CUBIC:
            
                tweenClassRef = Cubic;
                break;
                
            case Tween.STYLE_QUAD:
            
                tweenClassRef = Quad;
                break;
                
            case Tween.STYLE_QUART:
            
                tweenClassRef = Quart;
                break;
                
            case Tween.STYLE_QUINT:
            
                tweenClassRef = Quint;
                break;
                
            case Tween.STYLE_SINE:
            
                tweenClassRef = Sine;
                break;
            
            case Tween.STYLE_EXPO:
            
                tweenClassRef = Expo;
                break;
                    
            case Tween.STYLE_CIRC:
            
                tweenClassRef = Circ;
                break;
                
            case Tween.STYLE_ELASTIC:
            
                tweenClassRef = Elastic;
                break;
                
            case Tween.STYLE_BACK:
            
                tweenClassRef = Back;
                break;
                
            case Tween.STYLE_BOUNCE:    
            
                tweenClassRef = Bounce;
                break;
            
        }
        
    }
    
    //
    //
    private function getEaseMethod ():Void {
        
        switch (_easeType) {
            
            case Tween.EASE_IN:
            
                easeMethod = "easeIn";
                break;
                
            case Tween.EASE_OUT:
            
                easeMethod = "easeOut";
                break;
                
            case Tween.EASE_INOUT:
            
                easeMethod = "easeInOut";
                break;
            
        }
        
    }
    
    //
    //
    public function ease ():Void {
        
        var tweenVal:Number;
        
        if (_startTime == null) {
            _startTime = _parentClass.time + _delay;
        }
        
        _time = _parentClass.time - _startTime;
        
        if (_time < 0) return;
        
        if (!_started) onStart();
        
        var t:Number = 0;
        
        if (_done || clip == undefined) {
            clear();
            return;
        }
        
        if (_time <= _duration) {
            
            t = _time;
            
        } else {
            
            t = _duration;
            _done = true;
            
        }
        
        tweenVal = tweenClassRef[easeMethod](t, _startVal, _endVal, _duration);
        
        if (_tweenHandler != undefined) tweenVal = _tweenHandler(tweenVal);

        if (_attribute != "scale") {
            _clip[attribute] = tweenVal;
        } else {
            _clip._xscale = _clip._yscale = tweenVal;
        }

        if (_pixelSnap && (attribute == "_x" || attribute == "_y")) _clip[attribute] = Math.round(_clip[attribute]);
        
        if (_done) onDone();
        
    }
    
    //
    //
    private function onStart ():Void {
        
        _started = true;
        if (_startHandler != null) _startHandler.apply();
        
    }
    
    //
    //
    private function onDone ():Void {
        
        if (_doneHandler != null) _doneHandler.apply();
        clear();
        
    }
    
    //
    //
    public function clear ():Void {
        _parentClass.removeTween(this);
    }
    
}